/**
 * 
 * @author Go Media www.gomedia.co.za | info@gomedia.co.za
 * Copyright (c) 2010 Go Media (www.gomedia.co.za)
 * 
 * @version Beta
 * 
 * @fileOverview Application core
 * 
 **/

(function($) {

    /** @class The application core manages creation and caching of objects and templates */
    
    function gmwk() {
    
        /** 
         * @description Private variables
         * @private
         */
        var self = this;
        var sJSLibPath = "";
        var sJSLocalLibPath = "";
        var sTemplatePath = "";
        var nVersion = 0.1;
        var bLiveEnvironment = false;
        var bDebugStatus = true;
        var jqTemplateContainer;
        var jqStageContainer;
        var TemplateCache = {};
        var nTemplateCounter = 0;
        var aStack = [];
        
        /** 
         * @description Class cache
         * @public
         */
        this.classes = {};
        
        /** 
         * @description Utility functions
         * @public
         */
        this.utils = {};
    
        /**
         * @public
         * @param {String} sMyJSLibPath Global Javascript library path  
         */
        this.setLibPath = function(sMyJSLibPath) {
            sJSLibPath = sMyJSLibPath;
        };
    
        /**
         * @public
         * @param {String} sMyJSLocalPath Local Javascript library path 
         */
        this.setLocalPath = function(sMyJSLocalPath) {
            sJSLocalLibPath = sMyJSLocalPath;
        };
        
        /**
         * @public
         * @param {String} sMyTemplatePath Template path  
         */
        this.setTemplatePath = function(sMyTemplatePath) {
            sTemplatePath = sMyTemplatePath;
        };
        
        /**
         * @public
         * @param {Number} nMyVersion The version of this application 
         */
        this.setVersion = function(nMyVersion) {
            nVersion = nMyVersion;
        };
        
        /**
         * @public
         * @param {Boolean} bMyLiveEnvironment This must be set to true on the live system
         */
        this.setLiveEnvironment = function(bMyLiveEnvironment) {
            bLiveEnvironment = bMyLiveEnvironment;
        };
        
        /**
         * @public
         * @param {Boolean} bMyDebugStatus This must be set to false on the live system
         */
        this.setDebugStatus = function(bMyDebugStatus) {
            bDebugStatus = bMyDebugStatus;
        };
        
        /**
         * @public
         * @param {jQuery} jqMyTemplateContainer Holder for templates
         */
        this.setTemplateContainer = function(jqMyTemplateContainer) {
            jqTemplateContainer = jqMyTemplateContainer;
        };
        
        /**
         * @public
         * @param {jQuery} jqMyStageContainer Holder for stage   
         */
        this.setStageContainer = function(jqMyStageContainer) {
            jqStageContainer = jqMyStageContainer;
        };
        
        /** @public */
        this.init = function() {
            fInitConsole();
        };
        
        /**
         * @public
         * @returns {Number} Current version or random number for cache 
         */
        this.getVersion = function() {
            if (bLiveEnvironment) {
                return nVersion;
            } else {
                return ((new Date()).getTime());
            }
        };
    
        /**
         * @public
         * @returns {Boolean} Debug Status 
         */
        this.getDebugStatus = function() {
            return bDebugStatus;
        };
        
        /**
         * @public
         * @returns {jQuery} Template container 
         */
        this.getTemplateContainer = function() {
           return jqTemplateContainer;
        };
        
        /**
         * @public
         * @returns {jQuery} Stage container 
         */
        this.getStageContainer = function() {
            return jqStageContainer;
        };
        
        /** @public */
        this.clearStage = function(){
            jqStageContainer.empty();
        };
            
        /** 
         * @description Create an instance of a class, load the class if it is not cached
         * @public 
         * @param {String} sClassName Name of the class to create
         * @param {Object} Options Options to pass to the class constructor 
         * @param {Boolean} Options.bSingleton 
         * @param {String} Options.sTemplate
         * @param {Object} Options.jqParentContainer
         * @param {Object} Options.Arguments
         * @returns {Object} New instance of a class
         */
        this.create = function(sClassName, Options) {
            if (typeof(Options) == "undefined") {
               Options = {};
            }
            if (self.classes[sClassName] != undefined) {
                return fCreateClass(sClassName, Options);
            } else {
                fLoadClass(sClassName)
                return fCreateClass(sClassName, Options);
            }
        };
    
        /** 
         * @description Fetch the cached HTML template element wrapped in jQuery, load the template if not cached
         * @public 
         * @param {String} sClassName Name of the class template
         * @returns {jQuery} Template element wrapped in jQuery
         */
        this.getTemplate = function(sClassName) {
            if (TemplateCache[sClassName] == undefined) {
                var jqTemplate = jqTemplateContainer.find(".gmwk_template_" + sClassName);
                if (jqTemplate.length == 0) {
                    // Load template with AJAX call
                    fLoadTemplate(sClassName);
                } else {
                    // Template already loaded into the DOM
                    TemplateCache[sClassName] = jqTemplate;
                }
            }
            return TemplateCache[sClassName];
        };
        
        /** 
         * @description Clone the template the given container and give it a unique ID
         * @public 
         * @return {jQuery} A new template container 
         */
        this.cloneTemplate = function(sClassName, jqContainer) {
            nTemplateCounter++;
            self.getTemplate(sClassName)
                .clone()
                .attr("id", "gmwk_" + sClassName + "_" + nTemplateCounter)
                .addClass("gmwk_object_container")
                .appendTo(jqContainer);
            return jqContainer.find("#gmwk_" + sClassName + "_" + nTemplateCounter);
        }
        
        this.closestObjectContainer = function(jqElement) {
            return jqElement.closest(".gmwk_object_container").attr("id");
        }
        
        /**
         * @description Define console if not available
         * @private 
         */
        function fInitConsole() {
            if (typeof window.console == 'undefined' || !bDebugStatus) {
                if (!window.console) {
                    window.console = {};
                }
                window.console.log = function(msg) {};
                window.console.info = function(msg) {};
                window.console.warn = function(msg) {};
                window.console.error = function(msg) {};
                window.console.time = function(msg) {};
                window.console.timeEnd = function(msg) {};
                window.console.profile = function(msg) {};
                window.console.profileEnd = function(msg) {};
                window.console.group = function(msg) {};
                window.console.groupEnd = function(msg) {};
                window.console.trace = function(msg) {};
                window.console.dir = function(msg) {};
            }
        }
    
        /** 
         * @description Sync ajax call to fetch template into cache
         * @private 
         */
        function fLoadTemplate(sClassName) {
            console.info(sTemplatePath + sClassName + ".html?_=" + self.getVersion());
            $.ajax(
                {
                    url : sTemplatePath + sClassName + ".html?_=" + self.getVersion(),
                    success : function(Data) {
                        if (typeof TemplateCache[sClassName] == "undefined") { 
                            TemplateCache[sClassName] = {};
                        }
                        jqTemplateContainer.append(Data);
                        var jqTemplate = jqTemplateContainer.find("> :last");
                        TemplateCache[sClassName] = jqTemplate;
                    },
                    dataType: "html",
                    async : false
                }
            );
        }
        
    
        /** 
         * @description Loads class from server
         * @private
         */
        function fLoadClass(sClassName, sPath) {
            if (typeof sPath == "undefined") {
                sPath = sJSLocalLibPath;
            }
            $.ajax(
                {
                    url : sPath + sClassName + ".js?_=" + self.getVersion(),
                    success : function(Data) {
                        //alert("here" + Data);
                        // Allow class to cache itself
                        eval(Data);
                    },
                    error : function(XMLHttpRequest, errorType, exception) {
                        // File not found in local store try lib
                        if (sPath == sJSLocalLibPath) {
                            fLoadClass(sClassName, sJSLibPath);
                        // File not found in lib
                        } else {
                            alert(sClassName + " could not be found");
                        }
                    },
                    async : false
                }
            );
        }
        
        /** 
         * @private
         * @param {String} sClassName Class Name
         * @param {Object} Options Options to create with
         * @return {Object} class
         * 
         **/
        function fCreateClass(sClassName, Options) {
            Options.sClassName = sClassName;
            if (
                Options.sTemplate !== undefined && 
                Options.jqParentContainer !== undefined
            ) {
                Options.jqObjectContainer = self.cloneTemplate(Options.sTemplate, Options.jqParentContainer);
            }
            if (Options.bSingleton) {
                self[sClassName] = new self.classes[sClassName](Options);
            } else { 
                return new self.classes[sClassName](Options);
            }            
        }
      
    }
  
    window.gmwk = new gmwk();
    window.gmwk.init();

})(jQuery);


